﻿//-----------------------------------------------------------------------------------------------------------
// Wbfs Engine (WBFSe) Project by Omega Frost 
// http://wbfse.codeplex.com/
//
// WBFSe is Licensed under the terms of the 
// Microsoft Reciprocal License (Ms-RL)
//-----------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using WBFSe.IO;

namespace WBFSe.Data
{
    /// <summary>
    /// Node structure for file indexing
    /// </summary>
    class IndexNode : IComparer<IndexNode>
    {
        // Variables

        public String Path;
        public List<IndexNode> Nodes;
        public List<IWbfsFileInfo> Files;
        public List<NamePointer> Filenames;

        // Properties

        /// <summary>
        /// Checks if the node is empty
        /// </summary>
        public bool IsEmpty
        {
            get
            {
                return (this.Nodes.Count == 0) &&
                    (this.Files.Count == 0);
            }
        }

        // Methods

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="path">Path segment of the node</param>
        public IndexNode(String path)
        {
            this.Path = path;
            this.Nodes = new List<IndexNode>();
            this.Files = new List<IWbfsFileInfo>();
            this.Filenames = new List<NamePointer>();
        }

        /// <summary>
        /// Adds a file to the node
        /// </summary>
        /// <param name="file">File</param>
        public void AddFile(IWbfsFileInfo file)
        {
            int findex = this.Files.BinarySearch(file);
            
            if(findex >= 0) throw new ArgumentException(
                "Child file already exists");

            int[] pindex = new int[file.Filenames.Count];
            NamePointer[] np = new NamePointer[file.Filenames.Count];

            for (int i = 0; i < file.Filenames.Count; i++)
            {
                np[i] = new NamePointer(file.Filenames[i], file);
                pindex[i] = this.Filenames.BinarySearch(np[i], np[i]);

                if (pindex[i] >= 0) throw new ArgumentException(
                    "Child path already used by a file");
            }

            this.Files.Insert(~findex, file);

            for (int i = 0; i < pindex.Length; i++)
                this.Filenames.Insert(~pindex[i], np[i]);
        }

        /// <summary>
        /// Adds a node to the node
        /// </summary>
        /// <param name="name">Name</param>
        /// <returns>The created node</returns>
        public IndexNode AddNode(String name)
        {
            IndexNode node = new IndexNode(name);
            int nindex = this.Nodes.BinarySearch(node, node);

            if (nindex >= 0) throw new ArgumentException(
                 "Child node already exists");

            this.Nodes.Insert(~nindex, node);
            return node;
        }

        /// <summary>
        /// Removes a file from the node
        /// </summary>
        /// <param name="file">File</param>
        public void RemoveFile(IWbfsFileInfo file)
        {
            int findex = this.Files.BinarySearch(file);
            if (findex < 0) return;

            this.Files.RemoveAt(findex);

            for (int i = this.Filenames.Count - 1; i >= 0; i--)
            {
                if (this.Filenames[i].File == file)
                    this.Filenames.RemoveAt(i);
            }
        }

        /// <summary>
        /// Removes empty nodes from the tree
        /// </summary>
        public void Trim()
        {
            for (int i = this.Nodes.Count - 1; i >= 0; i--)
            {
                this.Nodes[i].Trim();
                if (this.Nodes[i].IsEmpty)
                    this.Nodes.RemoveAt(i);
            }
        }

        /// <summary>
        /// Returns a file containing the filename
        /// </summary>
        /// <param name="filename">Filename</param>
        /// <returns>IWbfsFile on success, null on failure</returns>
        public IWbfsFileInfo GetFile(String filename)
        {
            NamePointer n = new NamePointer(filename, null);
            int p = this.Filenames.BinarySearch(n, n);

            if (p >= 0) return this.Filenames[p].File;
            else return null;
            
        }

        /// <summary>
        /// Returns the node with the name
        /// </summary>
        /// <param name="name">Name of the node</param>
        /// <returns>IndexNode on success, null on failure</returns>
        public IndexNode GetNode(String name)
        {
            IndexNode n = new IndexNode(name);
            int p = this.Nodes.BinarySearch(n, n);

            if (p >= 0) return this.Nodes[p];
            else return null;

        }

        /// <summary>
        /// Compares 2 Nodes
        /// </summary>
        /// <param name="x">IndexNode</param>
        /// <param name="y">IndexNode</param>
        /// <returns>Path comparison</returns>
        public int Compare(IndexNode x, IndexNode y)
        {
            return x.Path.CompareTo(y.Path);
        }
    }
}
